package com.i2works.smartluolong.web.shiro;

import com.google.common.collect.Sets;
import com.i2works.smartluolong.utils.exception.ServiceException;
import com.i2works.smartluolong.web.entity.user.*;
import com.i2works.smartluolong.web.service.user.IUserAccountExtendService;
import com.i2works.smartluolong.web.service.user.IUserAccountService;
import com.i2works.smartluolong.web.service.user.IUserResService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 自定义shiro权限realm
 *
 * @author Liu Yutao koal@vip.qq.com
 * @date 2016/1/7 19:34
 */
public class SmartWebRealm extends AuthorizingRealm {

    @Autowired
    private IUserAccountService userAccountService;
    @Autowired
    private IUserAccountExtendService userAccountExtendService;
    @Autowired
    private IUserResService userResService;
    @Autowired
    private SessionDAO sessionDAO;
    @Autowired
    private RememberMeManager rememberMeManager;
    @Autowired
    CookieRememberMeManager cookieRememberMeManager;

    private SecureRandomNumberGenerator generator = new SecureRandomNumberGenerator();

    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 权限认证《获取授权URL连接》
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UserAccountDO userAccount = (UserAccountDO) SecurityUtils.getSubject().getPrincipals().iterator().next();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        try {
            //设置资源
            UserResQuery resQuery = new UserResQuery();
            resQuery.setAccountId(userAccount.getId());
            Set<UserResDO> resUserSet = userResService.queryUserResList(resQuery);
            Set<String> resSet = Sets.newLinkedHashSet();
            for (UserResDO UserResDo : resUserSet) {
                resSet.add(UserResDo.getResCode());
            }
            info.setStringPermissions(resSet);
//            //设置角色(如果不进行角色判断，可不设置)
//            UserRoleQuery roleQuery = new UserRoleQuery();
//            roleQuery.setAccountId(accountId);
//            Set<UserRoleDO> roleUserSet = userRoleService.queryList(roleQuery);
//            Set<String> roleSet = Sets.newLinkedHashSet();
//            for (UserRoleDO adminRoleDO : roleUserSet) {
//                roleSet.save(adminRoleDO.getRoleKey());
//            }
//             info.setRoles(roleSet);
        } catch (ServiceException e) {
            //e.printStackTrace();
            logger.error("SmartWebRealm.doGetAuthorizationInfo权限授权出错:", e.getMessage());
        }
        return info;
    }

    /**
     * 授权认证《获取权限角色》
     * 通过账号等账号信息，获取数据库账号信息，写入SimpleAuthenticationInfo发送到前台进行对比
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        UserAccountDO userAccount = null;
        try {
            //登录前获取当前用户是否已经登录了，如果登录就踢出他处状态，并在本次登录成功。
            //获取当前已登录的用户session列表
//            Collection<Session> sessions = sessionDAO.getActiveSessions();
//            for (Session session : sessions) {
//                //清除该用户以前登录时保存的session
//                Object attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
//                if (null != attribute) {
//                    SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) attribute;
//                    for (Object object : principalCollection) {
//                        if (object != null) {
//                            UserAccountDO sessionUser = (UserAccountDO) object;
//                            if (StringUtils.equalsIgnoreCase(userName, sessionUser.getUserName())) {
//                                // fixme session清除(无效)
//                                clearCachedAuthorizationInfo(principalCollection);
//                                clearCachedAuthenticationInfo(principalCollection);
//                                session.setTimeout(-1000);
//                                sessionDAO.delete(session);
//                                //必须重新根据ID获取session
//                                Session readSession = sessionDAO.readSession(session.getId());
//                                if (readSession != null) {
//                                    session.setAttribute(GlobalConstant.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE);
//                                }
//                            }
//                        }
//                    }
//                }
//            }
            userAccount = userAccountService.queryLoginUser(userName);
        } catch (ServiceException e) {
            logger.error("SmartWebRealm.doGetAuthorizationInfo权限授权出错:", e.getMessage());
        }
        if (null == userAccount) {
            throw new UnknownAccountException();//没找到帐号
        }
        if (userAccount.getStatus() == 0) {
            throw new LockedAccountException();//锁定
        }
        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userAccount, //用户信息，方便页面使用 <shiro:principal property="nickName"/>调用
                userAccount.getPassword(), //密码
                ByteSource.Util.bytes(userAccount.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        // 当验证都通过后，把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        UserAccountExtendQuery userAccountExtendQuery = new UserAccountExtendQuery();
        userAccountExtendQuery.setUserId(userAccount.getId());
        UserAccountExtendDO userAccountExtend = null;
        try {
            userAccountExtend = userAccountExtendService.query(userAccountExtendQuery);
        } catch (ServiceException e) {
            logger.error("获取用户扩展信息异常：" + e.getMessage());
        }
        if (userAccountExtend != null) {
            userAccount.setAvatar(userAccountExtend.getAvatar());
            userAccount.setRealName(userAccountExtend.getRealName());
        }
        session.setAttribute("userAccount", userAccount);
        return authenticationInfo;
    }


    /**
     * 清理授权缓存
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
        UserAccountDO userAccount = (UserAccountDO) principals.getPrimaryPrincipal();
        logger.info("用户：" + userAccount.getUserName() + " ==>清理授权缓存");
    }

    /**
     * 清理认证缓存
     * (cache key : 对象实例化字符串)
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        UserAccountDO userAccount = (UserAccountDO) principals.getPrimaryPrincipal();
        SimplePrincipalCollection spc = new SimplePrincipalCollection(userAccount, getName());
        super.clearCachedAuthenticationInfo(spc);
        logger.info("用户：" + userAccount.getUserName() + " ==>清理认证缓存");
    }


    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    private void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    private void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }


    /**
     * 清理授权缓存(用户)
     */
    public void clearUserCache() {
      this.clearCachedAuthenticationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    /**
     * 清理认证缓存(权限)
     */
    public void clearAuthorCache() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }


}
